package com.huazai.sangeng;

import com.huazai.domain.Author;
import com.huazai.domain.Book;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 重点笔记，skip和limit结合就相当于是分页查询了。
 * 惰性求值：如果没有终结操作，中间操作是不会得到执行的。
 * 流是一次性的：一旦一个流对象经过一次终结操作后。这个流就不能够再被使用。
 * 不会影响原来的数据（我们在流中可以多数据做很多的处理。但是在正常的情况下是不会影响原来集合中的数据。这往往也是符合我们的期望。）
 */
public class StreamDemo {

    public static void main(String[] args) {
        threadStreamTest();
    }

    private static void threadStreamTest() {

        // .parallel()是并行流调用的方法。之后会转为并行流。
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Optional<Integer> result = stream
                .parallel()
                .peek(num -> System.out.println(num + Thread.currentThread().getName()))
                .filter(num -> num > 5)
                .reduce(new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer result, Integer element) {
                        return result + element;
                    }
                });
        result.ifPresent(System.out::println);
    }

    private static void mapToNumberTest() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();

        /*
            在数据量大的时候因为有大量的，自动拆箱和装箱。所以会降低效率
         */
        authors.stream()
                .map(Author::getAge)
                .map(age -> age+10)
                .filter(age -> age>18)
                .map(age -> age + 2)
                .forEach(System.out::println);

        /*
            使用mapToInt把大量的数据直接转成了int型
         */
        authors.stream()
                .mapToInt(Author::getAge)
                .map(age -> age + 10)
                .filter(age -> age > 18)
                .map(age -> age+1)
                .forEach(System.out::println);
    }

    private static void testConstructorReference() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        authors.stream()
                .map(Author::getName)
                .map(StringBuilder::new)
                .map(stringBuilder -> stringBuilder.append("-seon").toString())
                .forEach(System.out::println);
    }

    private static void testAnd() {
        // 打印作家中年龄大于17并且姓名的长度大于1的作家。
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        authors.stream()
                .filter((author) -> {
                    return author.getAge() < 17;
                })

                .forEach(System.out::println);
    }

    /**
     * 深拷贝和浅拷贝
     */
    private static void test18() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        System.out.println("======================我是浅拷贝==================");
        authors.stream()
                .map(author -> author.getAge() + 10)
                .forEach(System.out::println);
        System.out.println(authors.get(0).getAge());

        System.out.println("======================我是深拷贝==================");
        authors.stream()
                .map(new Function<Author, Object>() {
                    @Override
                    public Integer apply(Author author) {
                        author.setAge(author.getAge() + 10);
                        return author.getAge();
                    }
                })
                .forEach(System.out::println);
        System.out.println(authors.get(0).getAge());
    }

    /**
     * reduce实例较难理解，需认真听讲
     * 需求一：使用reduce来求所有作家的年龄的和
     */
    private static void test17() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        Integer res = authors.stream()
                .distinct()
                .map(Author::getAge)
                .reduce(Integer.MAX_VALUE, (result, element) -> result < element? result: element);
        System.out.println(res);
    }

    private static void test16() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        Optional<Author> first = authors.stream()
                .sorted(((o1, o2) -> o2.getAge() - o1.getAge()))
                .findFirst();
        /*
        ifPresent（）方法可以有效滴防止空指针异常。
         */
        first.ifPresent(author -> System.out.println(author.getName()));

    }

    /**
     * 对match方法的学习。
     */
    private static void test15() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        boolean match = authors.stream()
                .noneMatch(author -> author.getAge() >= 100);

        System.out.println(match);
    }

    /**
     * 获取一个Map集合，map的key为作者名，value为List（Book）
     * 要注意的一个点是在转为map之前，最好是要把之前的数据去重一下
     * 在去重部分要注意的是
     * 被驱虫的类最好要重写EqualS和HashCode方法。
     * 因为原本的Equals方法是通过比较地址位置来进行区分的。但是在本需求中，并不是这样的。而是比较所有的属性值。如果都一样了。那两个对象就是相等的。
     */
    private static void test14() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        Map<String, List<Book>> collect = authors.stream()
                .distinct()
                .collect(Collectors.toMap(Author::getName, Author::getBooks));
    }

    /**
     * 获取一个作者集合的所有书籍的书名的Set
     */
    private static void test13() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        Set<String> collectSet = authors.stream()
                .map(Author::getName)
                .collect(Collectors.toSet());
        System.out.println(collectSet);
    }

    private static void test12() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();

        Optional<Integer> max = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .map(Book::getScore)
                .max((o1, o2) -> o1 - o2);
        Integer integer = max.get();

        System.out.println(integer);
    }

    private static void test11() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();

        long count = authors.stream()
                .map(Author::getName)
                .distinct()
                .count();
        System.out.println(count);
    }

    /**
     * flatMap其二。学习案例
     * 打印现有数据的所有分类，要求对分类进行去重。不能出现这中格式：哲学，爱情。
     */
    private static void test10() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
                .distinct()
                .forEach(System.out::println);
    }

    private static void test09() {
        /**
         * map可以把一个对象转换为另一个对象来作为流中的元素，而flatMap可以把一个对象转换为多个对象作为流中的元素。
         */
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        /**
         * 展开作家里的书籍信息，并且去重后打印
         */
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .forEach(System.out::println);
    }

    private static void test08() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        /**
         * skip方法可以用来跳过前n个元素。
         */
        authors.stream()
                .distinct()
                .sorted(((o1, o2) -> o1.getAge() - o2.getAge()))
                .skip(1)
                .forEach(System.out::println);
    }

    private static void test07() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        /**
         * 筛选出作家集合中年龄最大的作家。
         */
        authors.stream()
                .distinct()
                .sorted(((o1, o2) -> o2.getAge() - o1.getAge()))
                .limit(2)
                .forEach(System.out::println);
    }

    private static void test06() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        /**
         * sorted笔记：
         * 要求原本的集合中要去重
         * 如果sorted是空参方法的话，则需要自己的比较对象实现Comparable接口，实现对比的方法。
         */
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o1.getAge() - o2.getAge())
                .forEach(System.out::println);
    }

    private static void test05() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        authors.stream()
                .map(Author::getName)
                .distinct()
                .forEach(System.out::println);
    }

    private static void test04() {
        List<Author> authors = AuthorLIstGenerator.getAuthors();
        authors.stream()
                .map(Author::getAge)
                .map(age -> age + 10)
                .forEach(System.out::println);
    }

    private static void test03() {
        Map<Integer, Integer> map = new HashMap<>();
        map.put(11, 19);
        map.put(13, 17);
        map.put(12, 16);
        Stream<Map.Entry<Integer, Integer>> stream = map.entrySet().stream();
        map.entrySet().stream()
                .filter(item -> item.getValue() < 18)
                .forEach(System.out::println);

    }

    private static void test02() {
        Integer[] arr = {1,2,3,4,5};
        Stream<Integer> stream = Arrays.stream(arr);
        Stream<Integer> streamByStream = Stream.of(arr);
        stream.filter(entry -> entry > 2)
                .forEach(System.out::println);
    }


    /**
     * 我的天，流编程的效率真的好高啊！！！
     */
    private static void test01(List<Author> authors) {
        authors.stream()
                .distinct()
                .filter(author -> {
                    System.out.println("test");
                    return author.getAge() < 18;
                })
                .forEach(author -> System.out.println(author.getName())); // 终结操作，如果没有终结操作的话，就不会执行里面的方法。
    }

}
